package net;

import java.lang.reflect.InvocationTargetException;

public abstract class GameStateChange<A>
{
	public GameStateChange() {
		this(null, null, null);
	}

	public GameStateChange(core.GameObject subject, String propertyName, A argument) {
		setSubject(subject);
		setPropertyName(propertyName);
		setArgument(argument);
	}

	public core.GameObject getSubject() {
		return subject;
	}
	public void setSubject(core.GameObject subject) {
		this.subject = subject;
	}

	public String getPropertyName() {
		return propertyName;
	}
	public void setPropertyName(String name) {
		this.propertyName = name;
	}

	public A getArgument() {
		return argument;
	}
	public void setArgument(A primaryArgument) {
		this.argument = primaryArgument;
	}

	public Object execute() throws IllegalAccessException, InvocationTargetException, NoSuchMethodException {
		boolean foundName = false;
		for (java.lang.reflect.Method method : subject.getClass().getMethods())
			if (method.getName().equals(getMethodName()) && method.getParameterTypes().length == 1)
				try {
					foundName = true;
					return method.invoke(subject, new Object[] {argument});
				} catch (IllegalArgumentException e) {}

		if (!foundName)
			throw new NoSuchMethodException(getMethodName());
		throw new IllegalArgumentException(argument.toString());
	}

	public String toString() {
		return getSubject() + "." + getMethodName() + "(" + getArgument() + ")";
	}

	public abstract GameStateChange getInverse();

	protected abstract String getMethodName();

	private core.GameObject subject;
	private String propertyName;
	private A argument;
}